import 'dart:convert';
import 'dart:io';
import 'dart:math';

import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import '../utils/CommonUtils.dart';
import 'package:encrypt/encrypt.dart' as enc;
import 'package:encrypt/encrypt.dart';
import 'package:crypto/crypto.dart';

class EncryptUtils {
  static const ssssMethodChannel =
      MethodChannel('com.lilottery.workstation/ssss');
  static const String requestSingKey = 'sign';
  static const String requestSingMethodKey = 'sign_method';
  static const String singMethod = "MD5";
  static const String charsetType = "UTF-8";

  /// 打印日志
  static Future logD(msg) async {
    try {
      return ssssMethodChannel.invokeMethod('logD', {'log': msg});
    } on PlatformException catch (e) {
      debugPrint(e.toString());
      return '';
    }
  }

  /// 获取设备id
  static Future getUuid() async {
    try {
      return ssssMethodChannel.invokeMethod('getUuid');
    } on PlatformException catch (e) {
      debugPrint(e.toString());
      return '';
    }
  }

  /// 获取打包时间
  static Future getVersionTime() async {
    try {
      return ssssMethodChannel.invokeMethod('getVersionTime');
    } on PlatformException catch (e) {
      debugPrint(e.toString());
      return '';
    }
  }

  /// AES/CBC/NoPadding加密
  static Future encryptSSSS(String keyStr, String contentStr) async {
    try {
      return ssssMethodChannel.invokeMethod(
          'encryptSSSS', {'keyStr': keyStr, 'contentStr': contentStr});
    } on PlatformException catch (e) {
      debugPrint(e.toString());
      return '';
    }
  }

  /// AES/CBC/NoPadding解密
  static Future decryptSSSS(String keyStr, String contentStr) async {
    try {
      return ssssMethodChannel.invokeMethod(
          'decryptSSSS', {'keyStr': keyStr, 'contentStr': contentStr});
    } on PlatformException catch (e) {
      debugPrint(e.toString());
      return '';
    }
  }

  /// AES/CBC/NoPadding加密
  static String encrypt(String keyStr, String contentStr) {
    //初始化key和iv
    var keyBytes = utf8.encode(keyStr);
    IV iv = IV(Uint8List.fromList(keyBytes.sublist(0, 16)));
    //初始化内容
    var contentBytes = utf8.encode(contentStr);
    var lengthBytes = length2ByteEncodeList(contentBytes.length);
    // 1、得到key16+length4+content的字节码
    var contentNewBytes = keyBytes + lengthBytes + contentBytes;
    // 2、用PKCS7补充位移
    var pkcs7Bytes = pkcs7EncodeList(contentNewBytes.length);
    contentNewBytes += pkcs7Bytes;
    // 3、使用AES/CBC/NoPADDING加密
    final encryptor = Encrypter(
      AES(enc.Key.fromUtf8(keyStr), mode: AESMode.cbc, padding: null),
    );
    Encrypted resultBytes = encryptor.encryptBytes(contentNewBytes, iv: iv);
    // 4、将内容用base64的URL_SAFE模式转换
    String resultStr = base64.encode(resultBytes.bytes.toList());
    // 将+和/分别替换为- _两个字符 去掉=
    resultStr = resultStr
        .replaceAll('=', ' ')
        .replaceAll('+', '-')
        .replaceAll('/', '_').
        trim();
    return resultStr;
  }

  /// AES/CBC/NoPadding解密
  static String decrypt(String keyStr, String contentStr) {
    //初始化key和iv
    var keyBytes = utf8.encode(keyStr);
    IV iv = IV(Uint8List.fromList(keyBytes.sublist(0, 16)));
    int tempCount = contentStr.length % 4;
    if (tempCount > 0) {
      for (int i = 0; i < 4 - tempCount; i++) {
        contentStr += '=';
      }
    }
    // 1、将内容用base64的URL_SAFE模式解析
    Uint8List contentBytes =
        base64.decode(contentStr.replaceAll('-', '+').replaceAll('_', '/'));
    // 2、使用AES/CBC/NoPADDING解密
    final encryptor = Encrypter(
      AES(enc.Key.fromUtf8(keyStr), mode: AESMode.cbc, padding: null),
    );
    var resultBytes = encryptor.decryptBytes(Encrypted(contentBytes), iv: iv);
    // 3、用PKCS7去掉补充位移
    var resultNewBytes = pkcs7DecodeList(resultBytes);
    // 得到key16+length4+content的字节码，分开取出

    // String keyResultStr = utf8.decode(resultNewBytes.sublist(0, 16));
    var resultLength = byte2LengthDecodeList(resultNewBytes.sublist(16, 20));
    String tempResult =
        utf8.decode(resultNewBytes.sublist(20, 20 + resultLength));
    return tempResult;
  }

  static const int blockSize = 32;

  static List<int> pkcs7EncodeList(int length) {
// 计算需要填充的位数
    var amountToPad = blockSize - length % blockSize;
    if (amountToPad == 0) {
      amountToPad = blockSize;
    }
    String padChr = String.fromCharCode(amountToPad);
    var tmp = '';
    for (int i = 0; i < amountToPad; i++) {
      tmp += padChr;
    }
    return utf8.encode(tmp);
  }

  static List<int> pkcs7DecodeList(List<int> decrypted) {
    int pad = decrypted[decrypted.length - 1];
    if (pad < 1 || pad > 32) {
      pad = 0;
    }
    return decrypted.sublist(0, decrypted.length - pad);
  }

  ///将数据总长度的字节解密成数字
  static int byte2LengthDecodeList(List<int> orderBytes) {
    int sourceNumber = 0;
    for (int i = 0; i < 4; i++) {
      sourceNumber <<= 8;
      sourceNumber |= orderBytes[i] & 0xff;
    }
    return sourceNumber;
  }

  ///将数据总长度加密成4个字节
  static List<int> length2ByteEncodeList(int sourceNumber) {
    List<int> orderBytes = List<int>.filled(4, 0);
    orderBytes[3] = (sourceNumber & 0xFF);
    orderBytes[2] = (sourceNumber >> 8 & 0xFF);
    orderBytes[1] = (sourceNumber >> 16 & 0xFF);
    orderBytes[0] = (sourceNumber >> 24 & 0xFF);
    return orderBytes;
  }

  static String getRandomStr() {
    String base =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    Random random = Random();
    String str = '';
    for (int i = 0; i < 16; i++) {
      int number = random.nextInt(base.length);
      str += (base[number]);
    }
    return str;
  }

  static Future<String> getMd5(String path) async {
    File file = File(path);
    var digest = md5.convert(file.readAsBytesSync());
    // 这里其实就是 digest.toString()
    // return hex.encode(digest.bytes);
    return digest.toString();
  }

  //过滤，排序，签名，md5加密
  static String requestSign(Map<String, String> dataMap) {
    var filter = requestFilter(dataMap);
    var sortStr = requestSortString(filter);

    Uint8List sortBytes = Uint8List.fromList(utf8.encode(sortStr));
    Digest sortDigest = md5.convert(sortBytes);

    filter[requestSingKey] = sortDigest.toString();
    filter[requestSingMethodKey] = singMethod;

    var list = filter.keys.toList();
    list.sort();
    Map<String, String> sortMap = {};
    for (var element in list) {
      sortMap[element] = filter[element]!;
    }
    return json.encode(sortMap);
  }

  ///过滤空，和键为sign和sign_method
  static Map<String, String> requestFilter(Map<String, String> dataMap) {
    Map<String, String> result = {};
    if (dataMap.isNotEmpty) {
      for (var element in dataMap.keys) {
        String? value = dataMap[element];
        if (value != null &&
            value.isNotEmpty &&
            element != requestSingKey &&
            element != requestSingMethodKey) {
          result[element] = value;
        }
      }
    }
    return result;
  }

  //排序 拼接 私钥
  static String requestSortString(Map<String, String> dataMap) {
    var list = dataMap.keys.toList();
    list.sort();

    String sortStr = '';
    for (var element in list) {
      if (sortStr.isEmpty) {
        sortStr += '$element=${dataMap[element]!}';
      } else {
        sortStr += '&$element=${dataMap[element]!}';
      }
    }
    sortStr += '&key=${CommonUtils.appSecret}';
    return sortStr;
  }
}
